//
//  LKAnalyticesAction.m
//  LKAnalytics
//
//  Created by Eric MiAo on 16/9/7.
//  Copyright © 2016年 MiAo. All rights reserved.
//

#import "LKAnalyticesAction.h"
#import <UIKit/UIKit.h>
#import "sys/utsname.h"
#import <CoreTelephony/CTCarrier.h>
#import <CoreTelephony/CTTelephonyNetworkInfo.h>
#import "EMNetworking.h"

#import <SystemConfiguration/SystemConfiguration.h>
#import <netinet/in.h>

#import <arpa/inet.h>
#import <ifaddrs.h>
#import <netdb.h>
#import <sys/socket.h>
#import <netinet/in.h>

#import <CoreFoundation/CoreFoundation.h>




typedef enum : NSInteger {
    NotReachable = 0,
    ReachableViaWiFi,
    ReachableViaWWAN
} NetworkStatus;

#pragma mark IPv6 Support
//Reachability fully support IPv6.  For full details, see ReadMe.md.


extern NSString *kReachabilityChangedNotification;


@interface Reachability : NSObject

/*!
 * Use to check the reachability of a given host name.
 */
+ (instancetype)reachabilityWithHostName:(NSString *)hostName;

/*!
 * Use to check the reachability of a given IP address.
 */
+ (instancetype)reachabilityWithAddress:(const struct sockaddr *)hostAddress;

/*!
 * Checks whether the default route is available. Should be used by applications that do not connect to a particular host.
 */
+ (instancetype)reachabilityForInternetConnection;


#pragma mark reachabilityForLocalWiFi
//reachabilityForLocalWiFi has been removed from the sample.  See ReadMe.md for more information.
//+ (instancetype)reachabilityForLocalWiFi;

/*!
 * Start listening for reachability notifications on the current run loop.
 */
- (BOOL)startNotifier;
- (void)stopNotifier;

- (NetworkStatus)currentReachabilityStatus;

/*!
 * WWAN may be available, but not active until a connection has been established. WiFi may require a connection for VPN on Demand.
 */
- (BOOL)connectionRequired;

@end

#pragma mark IPv6 Support
//Reachability fully support IPv6.  For full details, see ReadMe.md.


NSString *kReachabilityChangedNotification = @"kNetworkReachabilityChangedNotification";


#pragma mark - Supporting functions

#define kShouldPrintReachabilityFlags 1

static void PrintReachabilityFlags(SCNetworkReachabilityFlags flags, const char* comment)
{
}


static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void* info)
{
#pragma unused (target, flags)
    NSCAssert(info != NULL, @"info was NULL in ReachabilityCallback");
    NSCAssert([(__bridge NSObject*) info isKindOfClass: [Reachability class]], @"info was wrong class in ReachabilityCallback");
    
    Reachability* noteObject = (__bridge Reachability *)info;
    // Post a notification to notify the client that the network reachability changed.
    [[NSNotificationCenter defaultCenter] postNotificationName: kReachabilityChangedNotification object: noteObject];
}


#pragma mark - Reachability implementation

@implementation Reachability
{
    SCNetworkReachabilityRef _reachabilityRef;
}

+ (instancetype)reachabilityWithHostName:(NSString *)hostName
{
    Reachability* returnValue = NULL;
    SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(NULL, [hostName UTF8String]);
    if (reachability != NULL)
    {
        returnValue= [[self alloc] init];
        if (returnValue != NULL)
        {
            returnValue->_reachabilityRef = reachability;
        }
        else {
            CFRelease(reachability);
        }
    }
    return returnValue;
}


+ (instancetype)reachabilityWithAddress:(const struct sockaddr *)hostAddress
{
    SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, hostAddress);
    
    Reachability* returnValue = NULL;
    
    if (reachability != NULL)
    {
        returnValue = [[self alloc] init];
        if (returnValue != NULL)
        {
            returnValue->_reachabilityRef = reachability;
        }
        else {
            CFRelease(reachability);
        }
    }
    return returnValue;
}


+ (instancetype)reachabilityForInternetConnection
{
    struct sockaddr_in zeroAddress;
    bzero(&zeroAddress, sizeof(zeroAddress));
    zeroAddress.sin_len = sizeof(zeroAddress);
    zeroAddress.sin_family = AF_INET;
    
    return [self reachabilityWithAddress: (const struct sockaddr *) &zeroAddress];
}

#pragma mark reachabilityForLocalWiFi
//reachabilityForLocalWiFi has been removed from the sample.  See ReadMe.md for more information.
//+ (instancetype)reachabilityForLocalWiFi



#pragma mark - Start and stop notifier

- (BOOL)startNotifier
{
    BOOL returnValue = NO;
    SCNetworkReachabilityContext context = {0, (__bridge void *)(self), NULL, NULL, NULL};
    
    if (SCNetworkReachabilitySetCallback(_reachabilityRef, ReachabilityCallback, &context))
    {
        if (SCNetworkReachabilityScheduleWithRunLoop(_reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode))
        {
            returnValue = YES;
        }
    }
    
    return returnValue;
}


- (void)stopNotifier
{
    if (_reachabilityRef != NULL)
    {
        SCNetworkReachabilityUnscheduleFromRunLoop(_reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
    }
}


- (void)dealloc
{
    [self stopNotifier];
    if (_reachabilityRef != NULL)
    {
        CFRelease(_reachabilityRef);
    }
}


#pragma mark - Network Flag Handling

- (NetworkStatus)networkStatusForFlags:(SCNetworkReachabilityFlags)flags
{
    PrintReachabilityFlags(flags, "networkStatusForFlags");
    if ((flags & kSCNetworkReachabilityFlagsReachable) == 0)
    {
        // The target host is not reachable.
        return NotReachable;
    }
    
    NetworkStatus returnValue = NotReachable;
    
    if ((flags & kSCNetworkReachabilityFlagsConnectionRequired) == 0)
    {
        /*
         If the target host is reachable and no connection is required then we'll assume (for now) that you're on Wi-Fi...
         */
        returnValue = ReachableViaWiFi;
    }
    
    if ((((flags & kSCNetworkReachabilityFlagsConnectionOnDemand ) != 0) ||
         (flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) != 0))
    {
        /*
         ... and the connection is on-demand (or on-traffic) if the calling application is using the CFSocketStream or higher APIs...
         */
        
        if ((flags & kSCNetworkReachabilityFlagsInterventionRequired) == 0)
        {
            /*
             ... and no [user] intervention is needed...
             */
            returnValue = ReachableViaWiFi;
        }
    }
    
    if ((flags & kSCNetworkReachabilityFlagsIsWWAN) == kSCNetworkReachabilityFlagsIsWWAN)
    {
        /*
         ... but WWAN connections are OK if the calling application is using the CFNetwork APIs.
         */
        returnValue = ReachableViaWWAN;
    }
    
    return returnValue;
}


- (BOOL)connectionRequired
{
    NSAssert(_reachabilityRef != NULL, @"connectionRequired called with NULL reachabilityRef");
    SCNetworkReachabilityFlags flags;
    
    if (SCNetworkReachabilityGetFlags(_reachabilityRef, &flags))
    {
        return (flags & kSCNetworkReachabilityFlagsConnectionRequired);
    }
    
    return NO;
}


- (NetworkStatus)currentReachabilityStatus
{
    NSAssert(_reachabilityRef != NULL, @"currentNetworkStatus called with NULL SCNetworkReachabilityRef");
    NetworkStatus returnValue = NotReachable;
    SCNetworkReachabilityFlags flags;
    
    if (SCNetworkReachabilityGetFlags(_reachabilityRef, &flags))
    {
        returnValue = [self networkStatusForFlags:flags];
    }
    
    return returnValue;
}


@end
#define LKAnalyticesVersion @"v2.0.1"
typedef enum {
    
    appLaunch = 0,        // app启动
    pageDuration = 1,    // 页面停留统计
    customEvent = 2,    // 自定义事件
    appEnd = 3,         // app关闭
    
} actionMode;

static NSString *_systemVersion;
static NSString *_uudi;
static NSString *_deviceVersion;
static NSString *_appKey;
static NSString *_appVersion;
static NSString *_userInfo;
static NSDictionary *_userDeviceDic;
static NSString *_sendIntervalStaticStr;
static ReportPolicy _rp;
static LKAnalyticesNotificationController *_notificationController;
@interface LKAnalyticesAction () {
    NSString *_appBeginTime;
    NSString *_appLaunchTime;
    BOOL _isAppActive;
    NSTimer *_sendTimer;
    NSString *_sendTime;
    double _sendInterval;
    Operating _operating;
    NSString *_devUrlStr;
    
    NSString *_regionStr;
    NSString *_areaStr;
    NSString *_countryStr;
    NSString *_cityStr;
    NSString *_region_id;
    NSString *_area_id;
    NSString *_country_id;
    NSString *_city_id;
    BOOL _debugMode;
}

@end


@implementation LKAnalyticesAction

#pragma mark -
#pragma mark - start

+ (instancetype)sharedAction {
    static LKAnalyticesAction *sharedAction = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedAction = [[self alloc] init];
    });
    return sharedAction;
}

- (void)developmentEnvironmentWithUrlPrefix:(NSString *)url {
    [[NSUserDefaults standardUserDefaults] setObject:@"1" forKey:@"LKAnalyticesDevUrl"];;
    _operating = DEVELOPMENT;
    _devUrlStr = url;
    [[NSUserDefaults standardUserDefaults] setObject:url forKey:@"LKAnalyticesDevUrl"];
}

- (void)startWithAppkey:(NSString *)appKey reportPolicy:(ReportPolicy)rp userInfo:(NSString *)userInfo {
    [[NSUserDefaults standardUserDefaults] setObject:appKey?appKey:@"" forKey:@"LKAnalyticesAppKey"];
    [self printVerdsionInfomation];
    [[NSUserDefaults standardUserDefaults] setObject:@"1" forKey:@"LKAnalyticesDevUrl"];
    _debugMode = NO;
    _operating = DISTRIBUTION;
    _appLaunchTime = [self getCurrentDateString];
    _rp = rp;
    _systemVersion = [[UIDevice currentDevice] systemVersion];
    _uudi = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
    _deviceVersion = [self deviceVersion];
    _appKey = appKey;
    _userInfo = userInfo;
    NSString *moblieConnection = [self isConnectionAvailable];
    _appVersion = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"];
    
    NSDictionary *appLaunchDic = @{
                                   @"osName":@"1",
                                   @"deviceId":_uudi,
                                   @"deviceName":_deviceVersion,
                                   @"osVersion":_systemVersion,
                                   @"mobileOperator":[self getMobileOperator],
                                   @"connection":moblieConnection,
                                   };
    _userDeviceDic = appLaunchDic;
    [[NSUserDefaults standardUserDefaults] setObject:appLaunchDic forKey:@"LKAnalyticsDeviceInfo"];
    
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        if ([[NSUserDefaults standardUserDefaults] objectForKey:@"LKAnalyticsLogArray"]) {
            [self debugLog:[NSString stringWithFormat:@"当前未发送log %@",[[NSUserDefaults standardUserDefaults] objectForKey:@"LKAnalyticsLogArray"]]];
        }else {
            [self debugLog:@"找不到本地log数组"];
        }
    });
    
    [self configurationMethod];
    if (rp == BATCH) {
        [self performSelector:@selector(sendLogToServer) withObject:nil afterDelay:2];
    } else if (rp == SENDWIFIONLY) {
        if ([moblieConnection isEqualToString:@"1"]) {
            [self performSelector:@selector(sendLogToServer) withObject:nil afterDelay:2];
        }
    }
    [self prepareCover];
}

- (void)configurationMethod {
    [[NSUserDefaults standardUserDefaults] setObject:@"400" forKey:@"LKAnalyticsPageDurationFlag"];
    [[NSUserDefaults standardUserDefaults] setObject:@"0.3" forKey:@"LKAnalyticesSendLatencySec"];
    _notificationController = [[LKAnalyticesNotificationController alloc]init];
    _notificationController.delegate = self;
    [[[[UIApplication sharedApplication] delegate] window] addObserver:self forKeyPath:@"rootViewController" options:NSKeyValueObservingOptionNew context:@"LKAnalyticsRootViewControllerChanged"];
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {
    if (context == @"LKAnalyticsRootViewControllerChanged") {
        [self debugLog:@"改变了window"];
        [self prepareCover];
    }
}

- (void)prepareCover {
    id rootVC = [[UIApplication sharedApplication].delegate window].rootViewController;
    UIViewController *systemVC;
    if ([rootVC isKindOfClass:[UINavigationController class]]) {
        UINavigationController *nav = (UINavigationController *)rootVC;
        systemVC = nav.viewControllers.firstObject;
    } else if ([rootVC isKindOfClass:[UITabBarController class]]) {
        UITabBarController *tab = (UITabBarController *)rootVC;
        systemVC = tab.viewControllers.firstObject;
    } else {
        systemVC = (UIViewController *)rootVC;
    }
    [systemVC addChildViewController:_notificationController];
    [systemVC.view addSubview:_notificationController.view];
    [systemVC.view sendSubviewToBack:_notificationController.view];
    
}

- (void)checkLogArrayHasBeRemovedByUnexpected {
    NSMutableArray *logArrayM;
    NSMutableArray *logTempArrayM;
    if (![[NSUserDefaults standardUserDefaults] objectForKey:@"LKAnalyticsLogArray"]) {
        
        logArrayM = [[NSMutableArray alloc]init];
        [[NSUserDefaults standardUserDefaults]setObject:logArrayM forKey:@"LKAnalyticsLogArray"];
        [self debugLog:@"添加时创建本地log数组"];
        if (![[NSUserDefaults standardUserDefaults] objectForKey:@"LKAnalyticsLogTempArray"]) {
            logTempArrayM = [[NSMutableArray alloc]init];
            [[NSUserDefaults standardUserDefaults]setObject:logTempArrayM forKey:@"LKAnalyticsLogTempArray"];
            [self debugLog:@"创建本地临时log数组"];
        }
    } else {
        logArrayM = [[NSMutableArray alloc]initWithArray:[[NSUserDefaults standardUserDefaults] objectForKey:@"LKAnalyticsLogArray"]];
        logTempArrayM = [[NSMutableArray alloc]initWithArray:[[NSUserDefaults standardUserDefaults] objectForKey:@"LKAnalyticsLogTempArray"]];
        if (logTempArrayM.count > 0) {
            [logArrayM addObjectsFromArray:logTempArrayM];
            [[NSUserDefaults standardUserDefaults]setObject:logArrayM forKey:@"LKAnalyticsLogArray"];
            [logTempArrayM removeAllObjects];
            [[NSUserDefaults standardUserDefaults]setObject:logTempArrayM forKey:@"LKAnalyticsLogTempArray"];
        }
    }
}

- (void)appLaunch {
    [self getAddress:^(NSString *region_id, NSString *region, NSString *area_id, NSString *area, NSString *country_id, NSString *country, NSString *city_id, NSString *city) {
        self->_regionStr = region;
        self->_areaStr = area;
        self->_countryStr = country;
        self->_cityStr = city;
        self->_region_id = region_id;
        self->_area_id = area_id;
        self->_country_id = country_id;
        self->_city_id = city_id;
    }];
    [self checkLogArrayHasBeRemovedByUnexpected];
    [self addLogToLogArrayWithActionName:appLaunch parameter:nil];
    if (_rp == SENDDAILY) {
        if ([self isNewDay]) {
            [self sendLogToServer];
        }
    }
    
}

- (void)getAddress:(void (^)(NSString *region_id, NSString *region, NSString *area_id, NSString *area, NSString *country_id, NSString *country, NSString *city_id, NSString *city))success {
    __block NSString *regionStr;
    __block NSString *areaStr;
    __block NSString *countryStr;
    __block NSString *cityStr;
    __block NSString *region_id;
    __block NSString *area_id;
    __block NSString *country_id;
    __block NSString *city_id;
    NSString *url;
    
    if (_operating == DEVELOPMENT) {
        url = _devUrlStr;
    } else {
        url = @"http://192.168.1.101:8081";
    }
    [self debugLog:[NSString stringWithFormat:@"获取位置url:%@", url]];

    EMHTTPSessionManager *manager = [EMHTTPSessionManager manager];
    manager.requestSerializer.timeoutInterval = 20;
    manager.requestSerializer = [EMJSONRequestSerializer serializer];//请求
//    manager.responseSerializer = [EMHTTPResponseSerializer serializer];//响应
    manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/html",@"text/json", @"text/javascript", nil];
    [manager GET:[NSString stringWithFormat:@"%@/boss/tracking/event/area",url] parameters:nil progress:^(NSProgress * _Nonnull uploadProgress) {
        
    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        [self debugLog:[NSString stringWithFormat:@"请求成功   %@",responseObject]];
        if ([[responseObject objectForKey:@"statusCode"] integerValue] == 200) {
            NSDictionary *dic = [responseObject objectForKey:@"data"];
            regionStr = [NSString stringWithFormat:@"%@",[dic objectForKey:@"region"]];
            areaStr = [NSString stringWithFormat:@"%@",[dic objectForKey:@"area"]];
            countryStr = [NSString stringWithFormat:@"%@",[dic objectForKey:@"country"]];
            cityStr = [NSString stringWithFormat:@"%@",[dic objectForKey:@"city"]];
            region_id = [NSString stringWithFormat:@"%@",[dic objectForKey:@"region_id"]];
            area_id = [NSString stringWithFormat:@"%@",[dic objectForKey:@"area_id"]];
            country_id = [NSString stringWithFormat:@"%@",[dic objectForKey:@"country_id"]];
            city_id = [NSString stringWithFormat:@"%@",[dic objectForKey:@"city_id"]];
            success(region_id, regionStr, area_id, areaStr, country_id, countryStr, city_id, cityStr);
        }else {
            success(@"",@"",@"",@"",@"",@"",@"",@"");
        }
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        [self debugLog:[NSString stringWithFormat:@"请求失败   %@",error]];
        success(@"",@"",@"",@"",@"",@"",@"",@"");
    }];
    
}

- (void)setLogSendInterval:(double)second {
    if (_rp == SEND_INTERVAL) {
        _sendInterval = second;
        _sendIntervalStaticStr = [NSString stringWithFormat:@"%f",second];
    }
}

- (void)setLatency:(NSInteger)second {
    __block NSInteger secondB = second;
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        if (secondB < 0) {
            secondB = 0;
        } else if (secondB > 1800) {
            secondB = 1800;
        }
        [[NSUserDefaults standardUserDefaults] setObject:[NSString stringWithFormat:@"%ld",(long)secondB] forKey:@"LKAnalyticesSendLatencySec"];
    });
    
}

- (void)logPageView:(NSString *)pageName seconds:(NSInteger)seconds {
    NSDictionary *dic = @{@"pageName":[NSString stringWithFormat:@"%ld",(long)seconds]};
    [self addLogToLogArrayWithActionName:pageDuration parameter:dic];
}

- (void)beginLogPageView:(NSString *)pageName {
    if (pageName == nil||[pageName isEqualToString:@""]||pageName == NULL||pageName.length == 0) {
        NSLog(@"LKError:页面名称不正确.\tthe pageName is not available");
    }else {
        [[NSUserDefaults standardUserDefaults] setObject:@"200" forKey:@"LKAnalyticsPageDurationFlag"];
        [[NSUserDefaults standardUserDefaults] setObject:pageName forKey:[NSString stringWithFormat:@"LKAnalyticsPageDuration_%@",pageName]];
        NSString *beginDate = [self getCurrentDateString];
        [[NSUserDefaults standardUserDefaults] setObject:beginDate forKey:[NSString stringWithFormat:@"LKAnalyticsPageBeginDate_%@",pageName]];
        [self debugLog:[NSString stringWithFormat:@"进入 %@  时间  %@",pageName,beginDate]];
        _notificationController.info = @{@"pageName" : pageName};
    }
}

- (void)endLogPageView:(NSString *)pageName {
    if ([[[NSUserDefaults standardUserDefaults] objectForKey:@"LKAnalyticsPageDurationFlag"] integerValue] == 200) {
        if ([[NSUserDefaults standardUserDefaults] objectForKey:[NSString stringWithFormat:@"LKAnalyticsPageBeginDate_%@",pageName]]&&[pageName isEqualToString:[[NSUserDefaults standardUserDefaults] objectForKey:[NSString stringWithFormat:@"LKAnalyticsPageBeginDate_%@",pageName]]]) {
            NSLog(@"LKError:两次方法传入的页面名称不一致.\tTwo pageName are inconsistent");
        }else {
            NSInteger beginDate = [[[NSUserDefaults standardUserDefaults] objectForKey:[NSString stringWithFormat:@"LKAnalyticsPageBeginDate_%@",pageName]] integerValue];
            NSInteger endDate = [[self getCurrentDateString] integerValue];
            double duration = endDate - beginDate;
            [self debugLog:[NSString stringWithFormat:@"进入 %ld  离开 %@  时间  %ld  停留 %f",(long)beginDate,pageName,(long)endDate,duration]];
            if (duration < 0) {
                duration = -duration;
            }
            duration = duration/1000;
            NSDictionary *dic = @{@"pageName":pageName,@"duration":[NSString stringWithFormat:@"%.3f",duration]};
            [self addLogToLogArrayWithActionName:pageDuration parameter:dic];
            [[NSUserDefaults standardUserDefaults] setObject:@"400" forKey:@"LKAnalyticsPageDurationFlag"];
            [[NSUserDefaults standardUserDefaults] removeObjectForKey:[NSString stringWithFormat:@"LKAnalyticsPageBeginDate_%@",pageName]];
        }
        
    }else {
        NSLog(@"LKError:页面统计方法不完整.\tThe method incomplete in page statistics");
    }
}



- (void)beginLogPageViewWhenAppDidBecomeActive:(NSString *)pageName {
    if ([[NSUserDefaults standardUserDefaults] objectForKey:[NSString stringWithFormat:@"LKAnalyticsPageDuration_%@",pageName]]) {
        if ([[[NSUserDefaults standardUserDefaults] objectForKey:[NSString stringWithFormat:@"LKAnalyticsPageDuration_%@",pageName]] isEqualToString:pageName]) {
            [[NSUserDefaults standardUserDefaults] setObject:@"200" forKey:@"LKAnalyticsPageDurationFlag"];
            UInt64 recordTime = [[NSDate date] timeIntervalSince1970]*1000;
            NSString *dateStr = [NSString stringWithFormat:@"%llu",recordTime];
            NSString *beginDate = dateStr;
            [[NSUserDefaults standardUserDefaults] setObject:beginDate forKey:[NSString stringWithFormat:@"LKAnalyticsPageBeginDate_%@",pageName]];
        }
    }
}


- (void)LKAnalyticesNotificationControllerReceive:(NSInteger)model :(NSDictionary *)info {
    [self debugLog:[NSString stringWithFormat:@"%ld  %@",(long)model,info]];
    if (model == 101) {
        _isAppActive = YES;
        _appBeginTime = [self getCurrentDateString];
        [self appLaunch];
        [self beginLogPageViewWhenAppDidBecomeActive:[info objectForKey:@"pageName"]];
        [self performSelector:@selector(timerMethod) withObject:nil afterDelay:0.3];
    }else if (model == 102) {
        [self endLogPageView:[info objectForKey:@"pageName"]];
        [self endApp];
        _isAppActive = NO;
    }else if (model == 103) {
        [self endApp];
        _isAppActive = NO;
    }
}

- (void)endApp {
    NSInteger endTime = [[self getCurrentDateString] integerValue];
    NSInteger beginTime = [_appBeginTime integerValue];
    double subTime = (endTime - beginTime)>0?(endTime - beginTime):(beginTime - endTime);
    
    subTime = subTime/1000;
    NSDictionary *dic = @{@"duration":[NSString stringWithFormat:@"%f",subTime]};
    [self addLogToLogArrayWithActionName:appEnd parameter:dic];
    if (_sendTimer) {
        [_sendTimer invalidate];
        _sendTimer = nil;
    }
    if (_rp == SEND_ON_EXIT) {
        [self sendLogToServer];
    }
}

- (void)event:(NSString *)eventId label:(NSString *)label attributes:(NSDictionary *)attributes {
    NSDictionary *dic = @{@"eventId":eventId,@"label":label,@"attributes":attributes==nil?@"":attributes};
    [self addLogToLogArrayWithActionName:customEvent parameter:dic];
    
}

- (void)debugModel {
    _debugMode = YES;
}

- (void)timerMethod {
    
    if (_rp == SEND_INTERVAL) {
        if (_sendInterval < 90) {
            _sendInterval = 90;
        }else if(_sendInterval > 86400) {
            _sendInterval = 86400;
        }
        if (_sendIntervalStaticStr == nil||_sendIntervalStaticStr.length == 0||[_sendIntervalStaticStr isEqualToString:@""]) {
            _sendIntervalStaticStr = @"180";
            _sendInterval = [_sendIntervalStaticStr doubleValue];
            NSLog(@"LKError:方法不完整.\tThe method incomplete");
        }
        if ([[self getCurrentDateString] doubleValue] - [_sendTime doubleValue] >= _sendInterval*1000) {
            [self sendLogToServer];
        }else {
            _sendInterval = ([[self getCurrentDateString] integerValue] - [_sendTime integerValue])/1000;
            _sendInterval = [_sendIntervalStaticStr integerValue] - _sendInterval;
            [self debugLog:[NSString stringWithFormat:@"_sendInterval = %f",_sendInterval]];
            [self debugLog:[NSString stringWithFormat:@"_sendInterval = %@ - %@",[self getCurrentDateString],_sendTime]];
        }
        [_sendTimer invalidate];
        _sendTimer = nil;
        
        _sendTimer = [NSTimer scheduledTimerWithTimeInterval:_sendInterval target:self selector:@selector(sendLogToServer) userInfo:nil repeats:YES];
        [self debugLog:[NSString stringWithFormat:@"------> %f",_sendInterval]];
    }
    
}

#pragma mark - tool

- (void)sendLogToServer {
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        NSInteger latencySec = [[[NSUserDefaults standardUserDefaults] objectForKey:@"LKAnalyticesSendLatencySec"] integerValue];
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(latencySec * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            NSString *url;
            if (self->_operating == DEVELOPMENT) {
                url = self->_devUrlStr;
            } else {
                url = @"http://192.168.10.42:8081";
            }
            [self debugLog:[NSString stringWithFormat:@"url:%@",url]];
            if (_rp == SEND_INTERVAL) {
                self->_sendInterval = [_sendIntervalStaticStr integerValue];
                [self->_sendTimer invalidate];
                self->_sendTimer = nil;
                self->_sendTimer = [NSTimer scheduledTimerWithTimeInterval:self->_sendInterval target:self selector:@selector(sendLogToServer) userInfo:nil repeats:YES];
            }
            
            if ([[NSUserDefaults standardUserDefaults] objectForKey:@"LKAnalyticsLogArray"]) {
                
                NSMutableArray *logArrayM = [[NSMutableArray alloc]initWithArray:[[NSUserDefaults standardUserDefaults] objectForKey:@"LKAnalyticsLogArray"]];
                
                [[NSUserDefaults standardUserDefaults]setObject:logArrayM forKey:@"LKAnalyticsLogTempArray"];
                
                [logArrayM removeAllObjects];
                
                [[NSUserDefaults standardUserDefaults]setObject:logArrayM forKey:@"LKAnalyticsLogArray"];
                [self debugLog:@"删除原先数据"];
                [self debugLog:@"执行log发送方法"];
                NSString *logTempArrayMStr = [self dictionaryToJson:[[NSMutableArray alloc]initWithArray:[[NSUserDefaults standardUserDefaults] objectForKey:@"LKAnalyticsLogTempArray"]]];
                
                
                EMURLSessionManager *manager = [[EMURLSessionManager alloc] initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
                NSMutableURLRequest *req = [[EMJSONRequestSerializer serializer] requestWithMethod:@"POST" URLString:[NSString stringWithFormat:@"%@/boss/tracking/event/upload",url] parameters:nil error:nil];
                req.timeoutInterval= [[[NSUserDefaults standardUserDefaults] valueForKey:@"timeoutInterval"] longValue];
                [req setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
                [req setValue:@"application/json" forHTTPHeaderField:@"Accept"];
                [req setHTTPBody:[logTempArrayMStr dataUsingEncoding:NSUTF8StringEncoding]];
                [[manager dataTaskWithRequest:req uploadProgress:nil downloadProgress:nil completionHandler:^(NSURLResponse * _Nonnull response, id  _Nullable responseObject, NSError * _Nullable error) {
                    if (!error) {
                        if ([[responseObject objectForKey:@"statusCode"] integerValue] == 200) {
                            [self debugLog:[NSString stringWithFormat:@"日志发送请求成功   %@",responseObject]];
                            self->_sendTime = [self getCurrentDateString];
                            [[NSUserDefaults standardUserDefaults] setObject:self->_sendTime forKey:@"LKAnalyticsLogSendTime"];
                            // 发送成功后清除临时队列数据
                            NSMutableArray *logTempArrayM = [[NSMutableArray alloc]init];
                            [[NSUserDefaults standardUserDefaults]setObject:logTempArrayM forKey:@"LKAnalyticsLogTempArray"];
                        } else {
                            [self debugLog:[NSString stringWithFormat:@"日志发送请求失败   %@",error]];
                            NSMutableArray *logArrayM_2 = [[NSMutableArray alloc]initWithArray:[[NSUserDefaults standardUserDefaults] objectForKey:@"LKAnalyticsLogArray"]];
                            NSMutableArray *logTempArray_2 = [[NSMutableArray alloc]initWithArray:[[NSUserDefaults standardUserDefaults] objectForKey:@"LKAnalyticsLogTempArray"]];
                            [logArrayM_2 addObjectsFromArray:logTempArray_2];
                            [[NSUserDefaults standardUserDefaults]setObject:logArrayM_2 forKey:@"LKAnalyticsLogArray"];
                            
                            // 发送失败后清除临时队列数据
                            [logTempArray_2 removeAllObjects];
                            [[NSUserDefaults standardUserDefaults]setObject:logTempArray_2 forKey:@"LKAnalyticsLogTempArray"];
                        }
                    } else {
                        [self debugLog:[NSString stringWithFormat:@"日志发送请求失败   %@",error]];
                        NSMutableArray *logArrayM_2 = [[NSMutableArray alloc]initWithArray:[[NSUserDefaults standardUserDefaults] objectForKey:@"LKAnalyticsLogArray"]];
                        NSMutableArray *logTempArray_2 = [[NSMutableArray alloc]initWithArray:[[NSUserDefaults standardUserDefaults] objectForKey:@"LKAnalyticsLogTempArray"]];
                        [logArrayM_2 addObjectsFromArray:logTempArray_2];
                        [[NSUserDefaults standardUserDefaults]setObject:logArrayM_2 forKey:@"LKAnalyticsLogArray"];
                        
                        // 发送失败后清除临时队列数据
                        [logTempArray_2 removeAllObjects];
                        [[NSUserDefaults standardUserDefaults]setObject:logTempArray_2 forKey:@"LKAnalyticsLogTempArray"];
                        
                    }
                }] resume];
 
            }else {
                NSMutableArray *logArrayM = [[NSMutableArray alloc]init];
                [[NSUserDefaults standardUserDefaults]setObject:logArrayM forKey:@"LKAnalyticsLogArray"];
                [self debugLog:@"创建本地log数组"];
                NSMutableArray *logTempArrayM = [[NSMutableArray alloc]init];
                [[NSUserDefaults standardUserDefaults]setObject:logTempArrayM forKey:@"LKAnalyticsLogTempArray"];
                [self debugLog:@"创建本地临时log数组"];
            }
        });
        [self debugLog:@"log准备发送"];
    });
}

- (void)addLogToLogArrayWithActionName:(actionMode)action parameter:(NSDictionary *)parameter {
    
    
    NSString *actionModeStr;
    switch (action) {
        case appLaunch:
            actionModeStr = @"appLaunch";
            break;
        case pageDuration:
            actionModeStr = @"pageDuration";
            break;
        case customEvent:
            actionModeStr = @"customEvent";
            break;
        case appEnd:
            actionModeStr = @"appEnd";
            break;
        default:
            break;
    }
    
    _regionStr = [self ifStringNull:_regionStr];
    _areaStr = [self ifStringNull:_areaStr];
    _countryStr = [self ifStringNull:_countryStr];
    _cityStr = [self ifStringNull:_cityStr];
    _region_id = [self ifStringNull:_region_id];
    _area_id = [self ifStringNull:_area_id];
    _country_id = [self ifStringNull:_country_id];
    _city_id = [self ifStringNull:_city_id];
    
    NSDictionary *logDic;
    
    if (parameter == nil||parameter == NULL) {
        logDic = @{@"action":actionModeStr,
                   @"device":_userDeviceDic,
                   @"date":[self getCurrentDateString],
                   @"appVersion":_appVersion,
                   @"appKey":_appKey,
                   @"userInfo":_userInfo,
                   @"region_id":_region_id,
                   @"region":_regionStr,
                   @"area_id":_area_id,
                   @"area":_areaStr,
                   @"country_id":_country_id,
                   @"country":_countryStr,
                   @"city_id":_city_id,
                   @"city":_cityStr,
                   @"parameter":@""
                   };
    }else {
        logDic = @{@"action":actionModeStr,
                   @"device":_userDeviceDic,
                   @"date":[self getCurrentDateString],
                   @"appVersion":_appVersion,
                   @"appKey":_appKey,
                   @"userInfo":_userInfo,
                   @"region_id":_region_id,
                   @"region":_regionStr,
                   @"area_id":_area_id,
                   @"area":_areaStr,
                   @"country_id":_country_id,
                   @"country":_countryStr,
                   @"city_id":_city_id,
                   @"city":_cityStr,
                   @"parameter":parameter};
    }
    NSMutableArray *logArrayM = [[NSMutableArray alloc]initWithArray:[[NSUserDefaults standardUserDefaults] objectForKey:@"LKAnalyticsLogArray"]];
    [logArrayM addObject:logDic];
    [[NSUserDefaults standardUserDefaults]setObject:logArrayM forKey:@"LKAnalyticsLogArray"];
    [self debugLog:@"加入一条log"];
    [self checkMaxData:512];
}

- (void)checkMaxData:(NSUInteger)maxCount {
    if (maxCount < 10) {
        maxCount = 10;
    }
    NSMutableArray *logArrayM = [[NSMutableArray alloc]initWithArray:[[NSUserDefaults standardUserDefaults] objectForKey:@"LKAnalyticsLogArray"]];
    if (logArrayM.count >= maxCount) {
        for (int i = 0; i < 10; i ++) {
            [logArrayM removeLastObject];
        }
    }
}

- (NSString *)ifStringNull:(NSString *)str {
    if (str.length == 0||[str isEqualToString:@"(null)"]||str == nil||str == NULL) {
        return @"";
    } else {
        return str;
    }
}

- (NSString*)deviceVersion {
    struct utsname systemInfo;
    uname(&systemInfo);
    NSString *deviceString = [NSString stringWithCString:systemInfo.machine encoding:NSUTF8StringEncoding];
    
    if ([deviceString isEqualToString:@"iPhone1,1"])    return @"iPhone 1G";
    if ([deviceString isEqualToString:@"iPhone1,2"])    return @"iPhone 3G";
    if ([deviceString isEqualToString:@"iPhone2,1"])    return @"iPhone 3GS";
    if ([deviceString hasPrefix:@"iPhone3"])            return @"iPhone 4";
    if ([deviceString isEqualToString:@"iPhone4,1"])    return @"iPhone 4S";
    if ([deviceString isEqualToString:@"iPhone5,1"]||[deviceString isEqualToString:@"iPhone5,2"])                               return @"iPhone 5";
    if ([deviceString isEqualToString:@"iPhone5,3"]||[deviceString isEqualToString:@"iPhone5,4"])    return @"iPhone 5C";
    if ([deviceString hasPrefix:@"iPhone6"]||[deviceString isEqualToString:@"iPhone6,1"]||[deviceString isEqualToString:@"iPhone6,2"])            return @"iPhone 5S";
    if ([deviceString isEqualToString:@"iPhone7,1"])    return @"iPhone 6 Plus";
    if ([deviceString isEqualToString:@"iPhone7,2"])    return @"iPhone 6";
    if ([deviceString isEqualToString:@"iPhone8,1"])    return @"iPhone 6S";
    if ([deviceString isEqualToString:@"iPhone8,2"])    return @"iPhone 6S Plus";
    if ([deviceString isEqualToString:@"iPhone8,4"]||[deviceString isEqualToString:@"iPhone8,3"])    return @"iPhone SE";
    if ([deviceString isEqualToString:@"iPhone9,1"]||[deviceString isEqualToString:@"iPhone9,3"])    return @"iPhone 7";
    if ([deviceString isEqualToString:@"iPhone9,2"]||[deviceString isEqualToString:@"iPhone9,4"])    return @"iPhone 7 Plus";
    if ([deviceString isEqualToString:@"iPhone10,1"]||[deviceString isEqualToString:@"iPhone10,4"])  return @"iPhone 8";
    if ([deviceString isEqualToString:@"iPhone10,5"]||[deviceString isEqualToString:@"iPhone10,2"])  return @"iPhone 8 plus";
    if ([deviceString isEqualToString:@"iPhone10,3"]||[deviceString isEqualToString:@"iPhone10,6"])  return @"iPhone X";
    
    
    if ([deviceString isEqualToString:@"iPod1,1"])      return @"iPod Touch 1G";
    if ([deviceString isEqualToString:@"iPod2,1"])      return @"iPod Touch 2G";
    if ([deviceString isEqualToString:@"iPod3,1"])      return @"iPod Touch 3G";
    if ([deviceString isEqualToString:@"iPod4,1"])      return @"iPod Touch 4G";
    if ([deviceString isEqualToString:@"iPod5,1"])      return @"iPod Touch 5G";
    if ([deviceString isEqualToString:@"iPod7,1"])      return @"iPod Touch 6G";
    if ([deviceString isEqualToString:@"iPad1,1"])      return @"iPad";
    if ([deviceString isEqualToString:@"iPad2,1"])      return @"iPad 2 (WiFi)";
    if ([deviceString isEqualToString:@"iPad2,2"])      return @"iPad 2 (GSM)";
    if ([deviceString isEqualToString:@"iPad2,3"])      return @"iPad 2 (CDMA)";
    if ([deviceString isEqualToString:@"iPad3,4"])      return @"iPad 4 (WiFi)";
    if ([deviceString isEqualToString:@"iPad3,5"])      return @"iPad 4 (GSM)";
    if ([deviceString isEqualToString:@"iPad3,6"])      return @"iPad 4 (CDMA)";
    if ([deviceString isEqualToString:@"iPad4,1"]||[deviceString isEqualToString:@"iPad4,2"]||[deviceString isEqualToString:@"iPad4,3"])      return @"iPad Air";
    if ([deviceString isEqualToString:@"iPad5,3"]||[deviceString isEqualToString:@"iPad5,4"])       return @"iPad Air2 ";
    if ([deviceString isEqualToString:@"iPad2,5"]||[deviceString isEqualToString:@"iPad2,6"]||[deviceString isEqualToString:@"iPad2,7"])      return @"iPad Mini";
    if ([deviceString isEqualToString:@"iPad4,4"]||[deviceString isEqualToString:@"iPad4,5"]||[deviceString isEqualToString:@"iPad4,6"])      return @"iPad Mini2";
    if ([deviceString isEqualToString:@"iPad4,7"]||[deviceString isEqualToString:@"iPad4,8"]||[deviceString isEqualToString:@"iPad4,9"])      return @"iPad Mini3";
    if ([deviceString isEqualToString:@"iPad5,1"]||[deviceString isEqualToString:@"iPad5,2"])      return @"iPad Mini4";
    if ([deviceString isEqualToString:@"iPad6,3"]||[deviceString isEqualToString:@"iPad6,4"]||[deviceString isEqualToString:@"iPad6,7"]||[deviceString isEqualToString:@"iPad6,8"]||[deviceString isEqualToString:@"iPad7,1"]||[deviceString isEqualToString:@"iPad7,2"]||[deviceString isEqualToString:@"iPad7,3"]||[deviceString isEqualToString:@"iPad7,4"])      return @"iPad Pro";
    
    if ([deviceString isEqualToString:@"i386"])         return @"Simulator";
    if ([deviceString isEqualToString:@"x86_64"])       return @"Simulator";
    
    
    
    return @"未知";
}

- (NSString *)isConnectionAvailable{
    
    NSString *isExistenceNetwork = @"0";
    Reachability *reach = [Reachability reachabilityWithHostName:@"www.baidu.com"];
    switch ([reach currentReachabilityStatus]) {
        case NotReachable:
            // 无网络
            isExistenceNetwork = @"0";
            
            break;
        case ReachableViaWiFi:
            // wifi
            isExistenceNetwork = @"1";
            
            break;
        case ReachableViaWWAN:
            // 3G
            isExistenceNetwork = @"2";
            
            break;
    }
    
    return isExistenceNetwork;
}


- (NSString *)getMobileOperator {
    CTTelephonyNetworkInfo *info = [[CTTelephonyNetworkInfo alloc] init];
    CTCarrier *carrier = [info subscriberCellularProvider];
    NSString *name = [NSString stringWithFormat:@"%@",[carrier carrierName]];
    if ([name isEqualToString:@"中国移动"]) {
        name = @"1";
    } else if ([name isEqualToString:@"中国联通"]) {
        name = @"2";
    } else if([name isEqualToString:@"中国电信"]){
        name = @"3";
    }
    return name;
}

- (NSString *)dictionaryToJson:(id)object {
    NSString *jsonString = [[NSString alloc]init];
    NSError *error;
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:object
                                                       options:NSJSONWritingPrettyPrinted
                                                         error:&error];
    if (! jsonData) {
        NSLog(@"error: %@", error);
    } else {
        jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
    }
    NSMutableString *mutStr = [NSMutableString stringWithString:jsonString];
    NSRange range = {0,jsonString.length};
    [mutStr replaceOccurrencesOfString:@" "withString:@""options:NSLiteralSearch range:range];
    NSRange range2 = {0,mutStr.length};
    [mutStr replaceOccurrencesOfString:@"\n"withString:@""options:NSLiteralSearch range:range2];
    return mutStr;
}

- (NSString *)getCurrentDateString
{
    UInt64 recordTime = [[NSDate date] timeIntervalSince1970]*1000;
    NSString *dateStr = [NSString stringWithFormat:@"%llu",recordTime];
    return dateStr;
}

- (NSString *)getCurrentDateWithDateString:(NSString *)dateString{
    double dateNum = dateString.length == 13?[dateString doubleValue]/1000:[dateString doubleValue];
    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
    [formatter setDateStyle:NSDateFormatterMediumStyle];
    [formatter setTimeStyle:NSDateFormatterShortStyle];
    [formatter setDateFormat:@"YYYY-MM-dd HH:mm:ss"];
    NSTimeZone* timeZone = [NSTimeZone timeZoneWithName:@"Asia/Shanghai"];
    [formatter setTimeZone:timeZone];
    NSDate *confromTimesp = [NSDate dateWithTimeIntervalSince1970:dateNum];
    NSString *confromTimespStr = [formatter stringFromDate:confromTimesp];
    return confromTimespStr;
}

- (BOOL)isNewDay {
    NSString *nowDateStr = [self getCurrentDateWithDateString:[self getCurrentDateString]];
    NSString *lastSendDateStr = [self getCurrentDateWithDateString:[[NSUserDefaults standardUserDefaults] objectForKey:@"LKAnalyticsLogSendTime"]];
    NSString *now = [[[nowDateStr componentsSeparatedByString:@"-"] objectAtIndex:2] substringToIndex:2];
    NSString *last = [[[lastSendDateStr componentsSeparatedByString:@"-"] objectAtIndex:2] substringToIndex:2];
    if ([now isEqualToString:last]) {
        return NO;
    }else {
        return YES;
    }
}

#pragma mark - POST
- (NSURLSessionDataTask *)POST:(NSString *)URLString
                        header:(NSDictionary *)header
                    parameters:(id)parameters
                       success:(void (^)(NSURLSessionDataTask *task, id responseObject))success
                       failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure {
    
    NSString *postPramstr = [self parseParams:parameters];
    NSURL *URL = [NSURL URLWithString:URLString];
    
    NSString *postString = postPramstr;
    NSData *postData = [postString dataUsingEncoding:NSUTF8StringEncoding];  //将请求参数字符串转成NSData类型
    
    NSMutableURLRequest *request = [[NSMutableURLRequest alloc]init];
    [request setHTTPMethod:@"POST"]; //指定请求方式
    [request setURL:URL]; //设置请求的地址
    [request setHTTPBody:postData];  //设置请求的参数
    [request setTimeoutInterval:20];
    [request setCachePolicy:1];
    if (header) {
        for (NSString *key in [header allKeys]) {
            [request setValue:header[key] forHTTPHeaderField:key];
        }
    }
    
    NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
    NSURLSession * session = [NSURLSession sessionWithConfiguration:configuration];
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    __block NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        
        if (!error) {
            NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil];
            
            success(task, dict);
        } else {
            failure(task, error);
        }
        
        dispatch_semaphore_signal(semaphore);
    }];
    
    [task resume];
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    
    return task;
}

/**
 *  格式化字符串
 *
 *  @param params 参数字典
 *
 *  @return 格式化字符串, username=LK&pwd=LK&type=JSON
 */
- (NSString *)parseParams:(NSDictionary *)params {
    NSString *keyValueFormat;
    NSMutableString *result = [NSMutableString new];
    NSMutableArray *array = [NSMutableArray new];
    //实例化一个key枚举器用来存放dictionary的key
    NSEnumerator *keyEnum = [params keyEnumerator];
    id key;
    while (key = [keyEnum nextObject]) {
        keyValueFormat = [NSString stringWithFormat:@"%@=%@", key, [params valueForKey:key]];
        [result appendString:keyValueFormat];
        [array addObject:keyValueFormat];
    }
    return result;
}

- (void)printVerdsionInfomation {
    NSLog(@"\n      \tLKAnalyticsVersion:\n\t----------  V2.0.1  ----------");
}

- (void)debugLog:(NSString *)log {
    if (_debugMode) {
        NSLog(@"%@",log);
    }
}

@end
